package oop.db.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import oop.controller.change.Change;
import oop.controller.change.ChangeDelegate;
import oop.data.Article;
import oop.db.Database;
import oop.util.Utils;

import com.google.gson.Gson;

public class ChangeDAO {

	public static Change fetchById(long changeId) throws Exception {
		Connection conn = null;
		PreparedStatement stmt = null;
		try {
			String sql = "SELECT chg_id, chg_user, chg_datetime, chg_comment, "
					+ "chg_namespace, chg_article, chg_minor, " +
							"chg_delegateclass, chg_delegatejson "
					+ "FROM tblChange " 
					+ "WHERE chg_id = ?";
			conn = Database.get().getConnection();
			stmt = conn.prepareStatement(sql);
			stmt.setLong(1, changeId);
			return Utils.single(fromStatement(stmt));
		} finally {
			if (stmt != null)
				stmt.close();
			if (conn != null)
				conn.close();
		}
	}
	
	public static List<Change> fetchByArticle(Article article) throws Exception {
		Connection conn = null;
		PreparedStatement stmt = null;
		try {
			String sql = "SELECT chg_id, chg_user, chg_datetime, chg_comment, "
					+ "chg_namespace, chg_article, chg_minor, " +
							"chg_delegateclass, chg_delegatejson "
					+ "FROM tblChange " 
					+ "WHERE chg_namespace = ? AND chg_article = ?";
			conn = Database.get().getConnection();
			stmt = conn.prepareStatement(sql);
			stmt.setLong(1, article.getNamespace().getId());
			stmt.setLong(2, article.getId());
			return fromStatement(stmt);
		} finally {
			if (stmt != null)
				stmt.close();
			if (conn != null)
				conn.close();
		}
	}

	private static List<Change> fromStatement(PreparedStatement stmt) throws Exception {
		ResultSet rs = null;
		try {
			rs = stmt.executeQuery();
			List<Change> result = new LinkedList<Change>();
			while (rs.next()) {
				ChangeDelegate delegate = (ChangeDelegate) new Gson().fromJson(
						rs.getString(9), Class.forName(rs.getString(8)));
				result.add(new Change(rs.getLong(1), rs.getLong(2), rs
						.getTimestamp(3), rs.getString(4), rs.getLong(5), rs
						.getLong(6), rs.getBoolean(7), delegate));
			}
			return result;
		} finally {
			if (rs != null)
				rs.close();
		}
	}

	public static Change create(long userId, Date datetime, String comment,
			long namespaceId, long articleId, boolean minor,
			ChangeDelegate delegate) throws Exception {
		Connection conn = null;
		PreparedStatement stmt = null;
		try {
			delegate.perform();

			String sql = "INSERT INTO tblChange (chg_user, chg_datetime, chg_comment, "
					+ "chg_namespace, chg_article, chg_minor, " +
							"chg_delegateclass, chg_delegatejson) " 
					+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
			
			conn = Database.get().getConnection();
			stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
			stmt.setLong(1, userId);
			stmt.setTimestamp(2, new Timestamp(datetime.getTime()));
			stmt.setString(3, comment);
			stmt.setLong(4, namespaceId);
			stmt.setLong(5, articleId);
			stmt.setBoolean(6, minor);
			stmt.setString(7, delegate.getClass().getName());
			stmt.setString(8, new Gson().toJson(delegate));
			stmt.executeUpdate();

			return new Change(Utils.getGeneratedKey(stmt), userId, datetime,
					comment, namespaceId, articleId, minor, delegate);
		} catch (Exception e) {
			conn.rollback();
			throw e;
		} finally {
			if (stmt != null)
				stmt.close();
			if (conn != null)
				conn.close();
		}
	}
	
}
